/*
 * 客户端节点每个监控项的消息事件同步机制
 * Copyright (C) 2009  YuLicheng
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.sysmo.server.node.item;

import java.util.HashMap;
import org.sysmo.communication.CommunicationProtocol;
import org.sysmo.server.node.item.ConnectedItem;
import org.w3c.dom.Document;

/**
 *
 * 客户端节点每个监控项的消息事件同步机制处理类。使用此类可对客户端通信同步。
 *
 * @author YuLicheng
 */
public class ItemEvent {

    //不支持泛型数组
    private static HashMap[] waitingItems =
            new HashMap[CommunicationProtocol.CLIENT_EVENT_NUMBER];
    static {
        for (int i = 0; i < waitingItems.length; i++) {
            waitingItems[i] = new HashMap();
        }
    }

    private static class EventAtom {
        public boolean flag;
        
        public EventAtom(Boolean flag) {
            this.flag = flag;
        }
    }

    /**
     * XML文档对象。
     */
    public Document messageDocument;
    private final static HashMap<Integer, EventAtom[]> eventLists = new HashMap<Integer, EventAtom[]>();
    private boolean eventOK = true;
    private ConnectedItem item = null;
    private EventAtom[] eventList;

    /**
     * 创建新的事件处理类。
     */
    public ItemEvent(ConnectedItem item) {
        this.item = item;
        synchronized (eventLists) {
            eventList = eventLists.get(item.getID());
            if (eventList == null) {
                eventList = new EventAtom[CommunicationProtocol.CLIENT_EVENT_NUMBER];
                for (int i = 0; i < eventList.length; i++) {
                    eventList[i] = new EventAtom(false);
                }
                eventLists.put(item.getID(), eventList);
            }
        }
    }

    public static void removeItem(int iid){
        synchronized (eventLists) {
            eventLists.remove(iid);
        }
    }

    /**
     * 等待指定类型的消息。
     *
     * @param event 要等待的消息类型。
     */
    public void waitEvent(int event) {
        if (event < 0 || event >= eventList.length) {
            return;
        }
        eventList[event].flag = true;
        try {
            synchronized (eventList[event]) {
                waitingItems[event].put(item.getID(), item);
                eventList[event].wait();
                waitingItems[event].remove(item.getID());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        eventList[event].flag = false;
    }

    /**
     * 退出消息处理。当等待的某个消息处理完成后，必须调用此方法以结束消息处理。
     */
    public void exitEvent() {
        eventOK = true;
    }


    /**
     * 处理客户端节点发送的事件。客户端节点对象负责对客户端发送的消息进行监听，然后
     * 将消息转发给对应的监控项对象。监控项对象在此对消息进行处理，若有相应的线程正
     * 在等待对应的消息则唤醒该线程，并且等待其处理完毕，若没有线程等待此消息则忽略。
     * 客户端节点对象在调用此方法后不会再对消息进行监听，此时只有当前的监控项对象独
     * 占客户端的通讯接口。
     *
     * @param messageDocument 消息文档对象。
     * @param itemID 对应的监控项ID。
     * @param request 消息类型号。
     */
    public static void doNodeMessage(Document messageDocument, int itemID,
            int request) {
        if (request < 0 || request >= waitingItems.length) {
            return;
        }
        ConnectedItem item = (ConnectedItem)waitingItems[request].get(itemID);
        if (item == null) {
            return;
        }
        item.event.doThisNodeMessage(messageDocument, request);
    }

    private void doThisNodeMessage(Document messageDocument, int request) {
        if (request < 0 || request >= eventList.length || !eventList[request].flag) {
            return;
        }
        this.messageDocument = messageDocument;
        eventOK = false;
        synchronized (eventList[request]) {
            eventList[request].notify();
        }
        try {
            while (!eventOK) {
                Thread.sleep(10);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //eventList[request].flag = false; //double check
        //this.messageDocument = null;
    }
}
